﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using BRbacSystem.Repositorys;
using System.Linq.Dynamic.Core;
using DefenseQuestion.Domain;

namespace DefenseQuestion.Repositorys
{
    public class BaseRepository<T> : IBaseRepository<T> where T : class
    {
        private readonly DefenseQuestionDbContext Context;
        private readonly IHttpContextAccessor httpContext;

        public DbSet<T> ety { get; }

        public BaseRepository(DefenseQuestionDbContext context, IHttpContextAccessor httpContext)
        {
            Context = context;
            this.httpContext = httpContext;
            ety = Context.Set<T>();
        }
        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public T Add(T entity)
        {
            using var transaction = Context.Database.BeginTransaction();
            try
            {
                
                ety.Add(entity);
                var list = Context.SaveChanges();
                transaction.Commit();
                return entity;
            }
            catch (Exception)
            {
                transaction.Rollback();

                throw;
            }
            
        }
        /// <summary>
        /// 异步添加
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<T> AddAsync(T entity)
        {
            using var transaction = Context.Database.BeginTransaction();
            try
            {
                Type type = entity.GetType();
                var PropCrateTime = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.CreateDate));
                if (PropCrateTime != null)
                {
                    PropCrateTime.SetValue(entity, DateTime.Now);
                }

                var headers = httpContext.HttpContext.Request.Headers;
                var user = httpContext.HttpContext.User.Identity.Name;
                var islogin = httpContext.HttpContext.User.Identity.IsAuthenticated;
                var claims = httpContext.HttpContext.User.Identities.First().Claims;


                var ProCreateName = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.CreateName));
                if (ProCreateName != null)
                    ProCreateName.SetValue(entity, user);

                ety.Add(entity);
                await Context.SaveChangesAsync();
                transaction.Commit();
                return entity;
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
          
        }
        /// <summary>
        /// 异步批量添加
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public async Task<int> AddManyAsync(List<T> entities)
        {
            Type type = entities.GetType();
            var PropCrateTime = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.CreateDate));
            if (PropCrateTime != null)
            {
                PropCrateTime.SetValue(entities, DateTime.Now);
            }

            var headers = httpContext.HttpContext.Request.Headers;
            var user = httpContext.HttpContext.User.Identity.Name;
            var islogin = httpContext.HttpContext.User.Identity.IsAuthenticated;
            var claims = httpContext.HttpContext.User.Identities.First().Claims;


            var ProCreateName = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.CreateName));
            if (ProCreateName != null)
                ProCreateName.SetValue(entities, user);
            await ety.AddRangeAsync(entities);
            return await Context.SaveChangesAsync();
        }
        /// <summary>
        /// 根据主键删除
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(int Id)
        {
            var t = Context.Database.BeginTransaction();
            try
            {
                Type type = typeof(T);
                var PropIsDeleted = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.IsDel));
                if (PropIsDeleted != null)
                {
                    var entity = await ety.FindAsync(Id);
                    PropIsDeleted.SetValue(entity, true);
                    var PropDeleteDate = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.DeleteDate));
                    if (PropDeleteDate != null)
                    {
                        PropDeleteDate.SetValue(entity, DateTime.Now);
                    }
                    var user = httpContext.HttpContext.User.Identity.Name;
                    var ProDeleteName = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.DeleteName));
                    if (ProDeleteName != null)
                        ProDeleteName.SetValue(entity, user);

                    ety.Update(entity);
                    t.Commit();
                    return await Context.SaveChangesAsync();
                }
                else
                {
                    var list = await ety.FindAsync(Id);
                    var PropDeleteDate = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.DeleteDate));
                    if (PropDeleteDate != null)
                    {
                        PropDeleteDate.SetValue(list, DateTime.Now);
                    }
                    var user = httpContext.HttpContext.User.Identity.Name;
                    var ProDeleteName = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.DeleteName));
                    if (ProDeleteName != null)
                        ProDeleteName.SetValue(list, user);

                    ety.Remove(list);
                    t.Commit();
                    return await Context.SaveChangesAsync();
                }
            }
            catch (Exception)
            {
                t.Rollback();
                throw;
            }
     
          
        }
        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(Expression<Func<T, bool>> where)
        {
            var list = await ety.Where(where).ToListAsync();
            ety.RemoveRange(list);
            return await Context.SaveChangesAsync();
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(List<T> entities)
        {
            ety.RemoveRange(entities);
            return await Context.SaveChangesAsync();
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<T> UpdateAsync(T entity)
        {
            var t = Context.Database.BeginTransaction();
            try
            {
                Type type = entity.GetType();
                var PropUpdateTime = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.UpdateDate));
                if (PropUpdateTime != null)
                {
                    PropUpdateTime.SetValue(entity, DateTime.Now);
                }

                var headers = httpContext.HttpContext.Request.Headers;
                var user = httpContext.HttpContext.User.Identity.Name;
                var islogin = httpContext.HttpContext.User.Identity.IsAuthenticated;
                var claims = httpContext.HttpContext.User.Identities.First().Claims;
                var ProUpdateName = type.GetProperties().FirstOrDefault(m => m.Name == nameof(Audit.UpdateName));
                if (ProUpdateName != null)
                    ProUpdateName.SetValue(entity, user);
                ety.Update(entity);
                await Context.SaveChangesAsync();
                t.Commit();
                return entity;
            }
            catch (Exception)
            {
                t.Rollback();
                throw;
            }




        }
        /// <summary>
        /// 根据主键查询
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<T> FindAsync(int Id)
        {
            return await ety.FindAsync(Id);
        }
        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<T> FindAsync(Expression<Func<T, bool>> where)
        {
            return await ety.FirstOrDefaultAsync(where);
        }
        /// <summary>
        /// 查询全部
        /// </summary>
        /// <returns></returns>
        public async Task<List<T>> QuerAsync()
        {

            return await ety.ToListAsync();
        }
        /// <summary>
        /// 预备查询全部
        /// </summary>
        /// <returns></returns>
        public  IQueryable<T> Queryable()
        {
            Type type=typeof(T);
            var PropIsDel = type.GetProperties().FirstOrDefault(x => x.Name == nameof(Audit.IsDel));
            if (PropIsDel != null)
            {
                return  ety.AsQueryable().Where("IsDel==false");
            }
            return ety.AsQueryable();
        }
        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<List<T>> QuerAsync(Expression<Func<T, bool>> where)
        {
            return await ety.Where(where).ToListAsync();
        }
        /// <summary>
        /// 是否存在记录
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<bool> ExistsAsync(Expression<Func<T, bool>> where)
        {
            return await ety.AnyAsync(where);
        }


    }
}
